package com.smart.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ExecutorBuilder;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.smart.common.EntranceLock;
import com.smart.common.enums.BooleanEnum;
import com.smart.common.enums.ErrorCode;
import com.smart.common.exception.BusinessException;
import com.smart.common.transfer.UnitTypeEnum;
import com.smart.common.utils.AssertUtil;
import com.smart.context.SessionContext;
import com.smart.mapper.JiansheProjectMapper;
import com.smart.mapper.ManageUserRegistrationMapper;
import com.smart.mapper.ProjectMapper;
import com.smart.mapper.UnitMapper;
import com.smart.model.convert.ManageUserRegistrationConvert;
import com.smart.model.convert.ProjectConvert;
import com.smart.model.domain.ManageUserRegistrationDO;
import com.smart.model.domain.ProjectDO;
import com.smart.model.domain.UnitDO;
import com.smart.model.dtomapper.ManageUserRegistrationDtoMapper;
import com.smart.model.request.ManageUserRegistrationRequest;
import com.smart.model.request.ProjectRequest;
import com.smart.model.vo.ManageUserRegistrationVO;
import com.smart.model.vo.ProjectVO;
import com.smart.model.vo.SuperviseManageCountVO;
import com.smart.service.ManageUserRegistrationService;
import com.smart.utils.BooleanUtil;
import com.smart.utils.DateUtils;
import com.smart.utils.StringUtil;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.stream.Collectors;

import static com.smart.utils.PageUtils.getOrderBy;

/**
 * @author zhanghong
 */
@Service
public class ManageUserRegistrationServiceImpl extends ServiceImpl<ManageUserRegistrationMapper, ManageUserRegistrationDO> implements ManageUserRegistrationService {
    @Autowired
    private ManageUserRegistrationMapper manageUserRegistrationMapper;
    @Autowired
    private ProjectMapper projectMapper;
    @Autowired
    private UnitMapper unitMapper;
    @Autowired
    private JiansheProjectMapper jiansheProjectMapper;
    @Autowired
    private EntranceLock entranceLock;

    private ExecutorService executorService = ExecutorBuilder.create().setCorePoolSize(5).setMaxPoolSize(10).setWorkQueue(new LinkedBlockingDeque<>(20000)).build();

    @Override
    public ManageUserRegistrationVO getByKey(long id) {
        ManageUserRegistrationDO manageUserRegistrationDO = getById(id);
        ManageUserRegistrationVO manageUserRegistrationVO = ManageUserRegistrationDtoMapper.INSTANCE.do2VO(manageUserRegistrationDO);
        return manageUserRegistrationVO;
    }

    /**
     * 云监管、云管理平台项目人员管理查询
     *
     * @param request
     * @return
     */
    @Override
    public PageInfo supervisePageQueryManage(ProjectRequest request) {
        Long jiansheUnitId = SessionContext.getJiansheUnitId();
        if (!ObjectUtils.isEmpty(jiansheUnitId)) {
            List<Long> projectIds = jiansheProjectMapper.selectAllProjectId(jiansheUnitId);
            if (!ObjectUtils.isEmpty(projectIds)) {
                request.setProjectIds(projectIds);
            }
        }
        Pair<Boolean, PageInfo> pair = getProjectVOS(request);
        Boolean pagin = pair.getLeft();
        PageInfo pageInfo = pair.getRight();
        List<ProjectVO> projectVOList = pageInfo.getList();

        // 查询信息
        List<ProjectVO> result = fillInfo(request, projectVOList);
        Boolean excludeIn = request.getExcludeIn();
        Boolean excludeOut = request.getExcludeOut();
        if (ObjectUtils.isEmpty(excludeIn)) {
            excludeIn = false;
        }
        if (ObjectUtils.isEmpty(excludeOut)) {
            excludeOut = false;
        }
        List<ProjectVO> page = projectVOList;
        List<ProjectVO> collect;
        if (excludeIn) {
            if (excludeOut) {
                collect = result.stream().filter(item -> item.getPersonCount() > 0 && (item.getInCount() > 0 || item.getOutCount() > 0))
                        .sorted(Comparator.comparing(ProjectVO::getCreateTime).reversed())
                        .collect(Collectors.toList());
                if (!pagin) {
                    page = ListUtil.page(request.getPageNum() - 1, request.getPageSize(), collect);
                }
            } else {
                collect = result.stream().filter(item -> item.getPersonCount() > 0)
                        .sorted(Comparator.comparing(ProjectVO::getCreateTime).reversed())
                        .collect(Collectors.toList());
                if (!pagin) {
                    page = ListUtil.page(request.getPageNum() - 1, request.getPageSize(), collect);
                }
            }
        } else {
            if (excludeOut) {
                collect = result.stream().filter(item -> item.getInCount() > 0 || item.getOutCount() > 0)
                        .sorted(Comparator.comparing(ProjectVO::getCreateTime).reversed())
                        .collect(Collectors.toList());
                if (!pagin) {
                    page = ListUtil.page(request.getPageNum() - 1, request.getPageSize(), collect);
                }
            } else {
                collect = result.stream().sorted(Comparator.comparing(ProjectVO::getCreateTime).reversed())
                        .collect(Collectors.toList());
                if (!pagin) {
                    page = ListUtil.page(request.getPageNum() - 1, request.getPageSize(), collect);
                }
            }
        }

        pageInfo.setList(page);
        pageInfo.setPageNum(request.getPageNum());
        pageInfo.setPages(request.getPageSize());
        if (pageInfo.getTotal() == 0) {
            pageInfo.setTotal(collect.size());
        }
        return pageInfo;
    }

    @NotNull
    private Pair<Boolean, PageInfo> getProjectVOS(ProjectRequest request) {
        List<ProjectDO> projectDOList;
        Boolean page = false;
        if (BooleanUtil.isTrue(request.getExcludeIn()) && BooleanUtil.isFalse(request.getExcludeOut())) {
            PageHelper.startPage(request.getPageNum(), request.getPageSize()).setReasonable(true);
            page = true;
            projectDOList = projectMapper.supervisePageQueryRecords2(request);
        } else {
            if (BooleanUtil.isFalse(request.getExcludeIn()) && BooleanUtil.isFalse(request.getExcludeOut())) {
                page = true;
                PageHelper.startPage(request.getPageNum(), request.getPageSize()).setReasonable(true);
            }
            projectDOList = projectMapper.supervisePageQueryRecords(request);
        }

        PageInfo pageInfo = new PageInfo();
        if (projectDOList instanceof Page) {
            pageInfo = new PageInfo<>(projectDOList);
            pageInfo.setList(ProjectConvert.buildProjectVoList(projectDOList));
        } else {
            pageInfo.setList(ProjectConvert.buildProjectVoList(projectDOList));
        }
        return Pair.of(page, pageInfo);
    }

    @NotNull
    private List<ProjectVO> fillInfo(ProjectRequest request, List<ProjectVO> projectVOList) {
        List<ProjectVO> result = Lists.newArrayList();
        if (request.getSuperviseOrManage()) {
            List<CompletableFuture<ProjectVO>> futureList = Lists.newArrayList();
            for (ProjectVO item : projectVOList) {
                CompletableFuture<ProjectVO> future = CompletableFuture.supplyAsync(() -> {
                    Long id = item.getId();
                    Date startTime = request.getStartTime();
                    Date endTime = request.getEndTime();
                    Integer in = manageUserRegistrationMapper.selectByTime2(startTime, endTime, id);
                    Integer out = manageUserRegistrationMapper.selectOutByTime(startTime, endTime, id);
                    Date lastUpdateTime = manageUserRegistrationMapper.selectLastUpdateTime(id);
                    //进场人次
                    item.setInCount(in);
                    //离场人次
                    item.setOutCount(out);
                    //最后更新时间
                    item.setLastUpdateTime(lastUpdateTime);
                    return item;
                }, executorService);
                futureList.add(future);
            }
            result = Lists.newArrayList();
            for (CompletableFuture<ProjectVO> future : futureList) {
                try {
                    result.add(future.get());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * 云监管项目人员管理查询统计
     *
     * @param request
     * @return
     */
    @Override
    public SuperviseManageCountVO supervisePageQueryManageCount(ProjectRequest request) {
        SuperviseManageCountVO countVO = new SuperviseManageCountVO();
        // 全区在监项目数量数量(在监：项目是有效的且项目状态为：非完工的)
        countVO.setProjectNum(projectMapper.countOnlineProject());
        // 全区项目人员在场人数合计
        countVO.setProjectPersonNum(manageUserRegistrationMapper.countOnlineProjectPersonCount());
        Date startTime = request.getStartTime();
        Date endTime = request.getEndTime();

        countVO.setConditionProjectNum(manageUserRegistrationMapper.countProjectCondition(startTime, endTime));
        countVO.setConditionInPersonNum(manageUserRegistrationMapper.countPersonNum(null, startTime, endTime, 1));
        countVO.setConditionOutPersonNum(manageUserRegistrationMapper.countPersonNum(null, startTime, endTime, 0));
        return countVO;
    }

    @Override
    public Integer countOnlineProjectPersonCount() {
        return manageUserRegistrationMapper.countOnlineProjectPersonCount();
    }

    /**
     * 人员是否已在场校验
     *
     * @param idCard
     * @param projectId
     * @return
     */
    @Override
    public Boolean entranceVerify(String idCard, Long projectId) {
        ManageUserRegistrationDO manageUserRegistrationDOS = manageUserRegistrationMapper.selectByIdCardAndProjectId(idCard, projectId, 1);
        AssertUtil.assertTrue(ObjectUtils.isEmpty(manageUserRegistrationDOS), "该人员当前在场，不能再次入场。");
        return true;
    }

    /**
     * 云监管、云监管、云管理项目人员进出场记录查询
     *
     * @param request
     * @param pageable
     * @return
     */
    @Override
    public PageInfo<List<ManageUserRegistrationVO>> supervisePageQueryRecords(ManageUserRegistrationRequest request, Pageable pageable) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        if (UnitTypeEnum.ZONGBAO.getNewType().equals(request.getUnitProperty())) {
            request.setZbUnitType(request.getUnitProperty());
            request.setUnitProperty(null);
        }
        List<ManageUserRegistrationDO> manageUserRegistrationDOList = manageUserRegistrationMapper.pageQueryByRequest(request);
        PageInfo pageInfo = new PageInfo(manageUserRegistrationDOList);
        List<ManageUserRegistrationVO> manageUserRegistrationVOList = ManageUserRegistrationConvert.buildManageUserRegistrationVoList(manageUserRegistrationDOList);
        fillInfo(manageUserRegistrationVOList);
        pageInfo.setList(manageUserRegistrationVOList);
        return pageInfo;
    }

    /**
     * 云服务人员进出场记录查询
     *
     * @param request
     * @param pageable
     * @return
     */
    @Override
    public PageInfo<List<ManageUserRegistrationVO>> supervisePageLists(ManageUserRegistrationRequest request, Pageable pageable) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        if (ObjectUtils.isEmpty(request.getProjectId())) {
            Long projectId = SessionContext.getProjectId();
            request.setProjectId(projectId);
        }
        List<ManageUserRegistrationDO> manageUserRegistrationDOList = manageUserRegistrationMapper.supervisePageLists(request);
        PageInfo pageInfo = new PageInfo(manageUserRegistrationDOList);
        List<ManageUserRegistrationVO> manageUserRegistrationVOList = ManageUserRegistrationConvert.buildManageUserRegistrationVoList(manageUserRegistrationDOList);
        fillInfo(manageUserRegistrationVOList);
        pageInfo.setList(manageUserRegistrationVOList);
        return pageInfo;
    }


    private void fillInfo(List<ManageUserRegistrationVO> manageUserRegistrationVOList) {

        for (ManageUserRegistrationVO vo : manageUserRegistrationVOList) {
            //单位信息
            Long unitId = vo.getUnitId();
            UnitDO unitDO = unitMapper.selectDOById(unitId);
            if (!ObjectUtils.isEmpty(unitDO)) {
                vo.setUnitName(unitDO.getUnitName());
                vo.setUnitDetailName(unitDO.getUnitDetailName());
                vo.setUnitProperty(unitDO.getUnitType());
            }
            //项目信息
            ProjectDO project = projectMapper.selectDOById(vo.getProjectId());
            if (project != null) {
                vo.setProjectName(project.getProjectName());
                vo.setProjectNumber(project.getProjectNumber());
                vo.setStreet(project.getStreetCode());
                vo.setEngineeringType(project.getEngineeringType());
                vo.setQualityRegistrationNumber(project.getQualityRegistrationNumber());
                vo.setShigongUnit(project.getShigongUnit());
            }

        }
    }

    /**
     * 云服务平台项目人员管理查询
     *
     * @param request
     * @param pageable
     * @return
     */
    @Override
    public PageInfo<List<ManageUserRegistrationVO>> cloudPageQueryManage(ManageUserRegistrationRequest request, Pageable pageable) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        request.setProjectId(SessionContext.getProjectId());
        if ("ZONGBAO_UNIT".equals(request.getUnitProperty())) {
            request.setZbUnitType(request.getUnitProperty());
            request.setUnitProperty(null);
        }
        List<ManageUserRegistrationDO> manageUserRegistrationDOList = manageUserRegistrationMapper.pageQueryManageByRequest(request);
        PageInfo pageInfo = new PageInfo(manageUserRegistrationDOList);
        List<ManageUserRegistrationVO> manageUserRegistrationVOList = ManageUserRegistrationConvert.buildManageUserRegistrationVoList(manageUserRegistrationDOList);
        manageUserRegistrationVOList.forEach(VO -> {
            Long unitId = VO.getUnitId();
            if (!ObjectUtils.isEmpty(unitId)) {
                UnitDO unitDO = unitMapper.selectDOById(unitId);
                if (!ObjectUtils.isEmpty(unitDO)) {
                    VO.setUnitName(unitDO.getUnitName());
                    VO.setUnitProperty(unitDO.getUnitType());
                }
            } else {
                ProjectDO projectDO = projectMapper.selectDOById(VO.getProjectId());
                VO.setUnitName(projectDO.getShigongUnit());
                VO.setUnitProperty("ZONGBAO_UNIT");
            }
        });
        pageInfo.setList(manageUserRegistrationVOList);
        return pageInfo;
    }

    @Override
    public List<ManageUserRegistrationVO> listQuery(ManageUserRegistrationRequest request) {
        List<ManageUserRegistrationDO> list = list();
        List<ManageUserRegistrationVO> manageUserRegistrationVOS = ManageUserRegistrationConvert.buildManageUserRegistrationVoList(list);
        return manageUserRegistrationVOS;
    }

    /**
     * 入场
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object entrance(ManageUserRegistrationRequest request) {
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getProjectId()), "项目id不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getUserPhone()), "手机号不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getJobType()), "职务不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getInoculateNumber()), "新冠疫苗接种针数不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getEntranceTime()), "进场时间不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getCommute()), "是否通勤不能为空");
        if (!"ZONGBAO_UNIT".equals(request.getUnitProperty())) {
            AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getUnitId()), "单位不能为空");
        }
        AssertUtil.assertTrue(StringUtil.isPhoneNumber(request.getUserPhone()), "手机号输入有误");
        String idCard = request.getIdCard();
        Long projectId = request.getProjectId();
        boolean locked = entranceLock.tryLock(idCard);
        AssertUtil.assertTrue(locked, "该人员正在办理入场中,请稍后!");
        try {
            ManageUserRegistrationDO manageUserRegistrationDOS = manageUserRegistrationMapper.selectByIdCardAndProjectId(idCard, projectId, 1);
            AssertUtil.assertTrue(ObjectUtils.isEmpty(manageUserRegistrationDOS), "该人员当前在场，不能再次入场。");
            ManageUserRegistrationDO manageUserRegistrationDO = ManageUserRegistrationDtoMapper.INSTANCE.request2DO(request);
            manageUserRegistrationDO.setCreateTime(DateUtils.getNowDate());
            manageUserRegistrationDO.setDeleted(BooleanEnum.FALSE.getCode());
            manageUserRegistrationDO.setLeaveOrNot(1);
            manageUserRegistrationDO.setUnitProperty(request.getUnitProperty());
            manageUserRegistrationMapper.insertManageUserRegistration(manageUserRegistrationDO);
        } finally {
            entranceLock.unlock(idCard);
        }
        return "办理入场成功";
    }

    /**
     * 离场
     *
     * @param request
     * @return
     */
    @Override
    public Object exit(ManageUserRegistrationRequest request) {
        String idCard = request.getIdCard();
        Long projectId = request.getProjectId();
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(idCard), "身份证号不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getProjectId()), "项目id不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getExitTime()), "离场时间不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getProvince()), "离场后居住地址不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getCity()), "离场后居住地址不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getArea()), "离场后居住地址不能为空");
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(request.getExitResideAddress()), "离场后居住地址不能为空");
        boolean locked = entranceLock.tryLock(idCard);
        AssertUtil.assertTrue(locked, "该人员正在办理离场中,请稍后!");
        try {
            ManageUserRegistrationDO manageUserRegistrationDOS = manageUserRegistrationMapper.selectByIdCardAndProjectId(idCard, projectId, 1);
            AssertUtil.assertTrue(!ObjectUtils.isEmpty(manageUserRegistrationDOS), "该人员非在场人员，不能办理离场。");
            Date entranceTime = manageUserRegistrationDOS.getEntranceTime();
            AssertUtil.assertTrue(entranceTime.getTime() < request.getExitTime().getTime(), "离场日期不能早于进场日期");
            ManageUserRegistrationDO manageUserRegistrationDO = ManageUserRegistrationDtoMapper.INSTANCE.request2DO(request);
            manageUserRegistrationDO.setUpdateTime(DateUtils.getNowDate());
            manageUserRegistrationDO.setLeaveOrNot(0);
            manageUserRegistrationDO.setId(manageUserRegistrationDOS.getId());
            manageUserRegistrationMapper.updateManageUserRegistration(manageUserRegistrationDO);
        } finally {
            entranceLock.unlock(idCard);
        }
        return "办理离场成功";
    }

    /**
     * 离场校验
     *
     * @param idCard
     * @param projectId
     * @return
     */
    @Override
    public ManageUserRegistrationVO exitVerify(String idCard, Long projectId) {
        ManageUserRegistrationDO manageUserRegistrationDO = manageUserRegistrationMapper.selectByIdCardAndProjectId(idCard, projectId, 1);
        if (manageUserRegistrationDO == null) {
            throw new BusinessException(ErrorCode.SUCCESS, "该人员非在场人员，不能办理离场。");
        }
        ManageUserRegistrationVO manageUserRegistrationVO = ManageUserRegistrationDtoMapper.INSTANCE.do2VO(manageUserRegistrationDO);
        Long unitId = manageUserRegistrationVO.getUnitId();
        if (unitId != null) {
            UnitDO unitDO = unitMapper.selectDOById(unitId);
            if (unitDO != null) {
                manageUserRegistrationVO.setUnitName(unitDO.getUnitName());
                manageUserRegistrationVO.setUnitDetailName(unitDO.getUnitDetailName());
                manageUserRegistrationVO.setUnitProperty(unitDO.getUnitType());
            }
        }
        return manageUserRegistrationVO;
    }

    @Override
    public Boolean deleteByKey(long id) {
        manageUserRegistrationMapper.deleteById(id);
        return true;
    }

}
